#pragma once
#include "../common/net.h"

#include "../common/message.h"

namespace rpc
{
    namespace server
    {
        enum class VType
        {
            BOOL = 0,
            INTEGRAL,
            NUMERIC,
            STRING,
            ARRAY,
            OBJECT,
        };
        class ServerDescribe
        {
        public:
            using ptr = std::shared_ptr<ServerDescribe>;
            using serviceCallback = std::function<void(const Json::Value &, Json::Value &)>;
            using ParamDescribe = std::pair<std::string, VType>;
            ServerDescribe(std::string &&name, std::vector<ParamDescribe> &&param, serviceCallback &&handler, VType type)
                : _method_name(std::move(name)), _callback(std::move(handler)), _return_type(type), _params_desc(std::move(param))
            {
            }
            const std::string &method()
            {
                return _method_name;
            }
            bool paramCheck(const Json::Value &param)
            {
                for (auto &desc : _params_desc)
                {
                    if (param.isMember(desc.first) == false)
                    {
                        ELOG("参数字段完整性校验失败！%s 字段缺失！", desc.first.c_str());
                        return false;
                    }
                    if (check(desc.second, param[desc.first] == false))
                    {
                        ELOG("%s 参数类型校验失败！", desc.first.c_str());
                        return false;
                    }
                }
                return true;
            }
            bool call(const Json::Value &param, Json::Value &result)
            {
                _callback(param, result);
                if (rtypeCheck(result) == false)
                {
                    ELOG("回调处理函数中的响应信息校验失败！");
                    return false;
                }
                return true;
            }

        private:
            bool rtypeCheck(const Json::Value &val)
            {
                return check(_return_type, val);
            }
            bool check(VType vtype, const Json::Value &val)
            {
                switch (vtype)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                }
                return false;
            }

        private:
            std::string _method_name;
            serviceCallback _callback;
            std::vector<ParamDescribe> _params_desc;
            VType _return_type;
        };
        class SDercribeFactory
        {
        public:
            void setMethodName(const std::string &name)
            {
                _method_name = name;
            }
            void setReturnType(VType type)
            {
                _return_type = type;
            }
            void setCallback(const ServerDescribe::serviceCallback &handler)
            {
                _callback = handler;
            }
            void setParam(std::string name, VType type)
            {
                _params_desc.push_back(ServerDescribe::ParamDescribe(name, type));
            }
            ServerDescribe::ptr build()
            {
                return std::make_shared<ServerDescribe>(std::move(_method_name), std::move(_params_desc), std::move(_callback), _return_type);
            }

        private:
            std::string _method_name;
            ServerDescribe::serviceCallback _callback;
            std::vector<ServerDescribe::ParamDescribe> _params_desc;
            VType _return_type;
        };
        class SerivceManager
        {
        public:
            using ptr = std::shared_ptr<SerivceManager>;
            void insert(const ServerDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service.insert(std::make_pair(desc->method(), desc));
            }
            ServerDescribe::ptr select(const std::string &method_name)
            {

                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _service.find(method_name);
                if (it == _service.end())
                {
                    DLOG("没有找到方法");
                    return ServerDescribe::ptr();
                }
                return it->second;
            }
            void remove(const std::string &method_name)
            {

                std::unique_lock<std::mutex> lock(_mutex);
                _service.erase(method_name);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServerDescribe::ptr> _service;
        };
        class RpcRouter
        {
        public:
            using ptr = std::shared_ptr<RpcRouter>;
            RpcRouter() : _service_manager(std::make_shared<SerivceManager>())
            {
            }
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request)
            {
                auto service = _service_manager->select(request->method());
                std::cout << "164 service" << request->method() << std::endl;
                if (service.get() == nullptr)
                {
                    ELOG("%s 服务未找到", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }
                if (service->paramCheck(request->params()) == false)
                {
                    ELOG("%s 服务参数校验失败", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INVALID_PARAMS);
                }
                Json::Value result;
                bool ret = service->call(request->params(), result);
                if (ret == false)
                {
                    ELOG("%s 服务参数校验失败！", request->method().c_str());
                    return response(conn, request, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }
                return response(conn, request, result, RCode::RCODE_OK);
            }
            void registerMethod(const ServerDescribe::ptr &service)
            {
                return _service_manager->insert(service);
            }

        private:
            void response(const BaseConnection::ptr &conn, const RpcRequest::ptr &req, const Json::Value &res, RCode code)
            {
                auto msg = rpc::MessageFactory::create<RpcResponse>();
                msg->setrId(req->rid());
                msg->Setresult(res);
                msg->SetRCode(code);
                msg->setMtype(lxprpc::MType::RSP_RPC);
                conn->send(msg);
            }

        private:
            SerivceManager::ptr _service_manager;
        };
    }
}